<template>
  <div>
    <!-- 多图片上传 -->
    <el-upload
      v-if="multiple"
      action="#"
      list-type="picture-card"
      accept="image/*"
      :on-preview="handlePreview"
      :before-upload="beforeUpload"
      :auto-upload="false"
      :on-remove="handleRemove"
      :http-request="uploadImage"
      :on-change="handleCrop"
      :file-list="uploadList"
    >
      <i class="el-icon-plus" />
    </el-upload>
    <!-- 单图片上传 -->
    <el-upload
      v-else
      ref="imageUploader"
      class="image-uploader"
      action="#"
      accept="image/*"
      list-type="picture-card"
      :on-preview="handlePreviewSingle"
      :before-upload="beforeUpload"
      :show-file-list="false"
      :auto-upload="false"
      :on-remove="handleRemove"
      :http-request="uploadImage"
      :on-change="handleCrop"
      :file-list="uploadList"
      :fixed-number="[1, 1]"
    >
      <img
        v-if="imageUrl"
        ref="singleImg"
        :src="imageUrl"
        :style="{width:width+'px',height:height+'px'}"
        class="avatar"
        @mouseenter="mouseEnter"
        @mouseleave="mouseLeave"
      >
      <i
        v-else
        class="el-icon-plus image-uploader-icon"
        :style="{width:width+'px',height:height+'px','line-height':height+'px','font-size':height/6+'px'}"
      />
      <div
        v-if="imageUrl"
        id="uploadIcon"
        ref="reupload"
        :style="{width:'100%'}"
        @mouseenter="mouseEnter"
        @mouseleave="mouseLeave"
      >
        <i
          class="el-icon-zoom-in"
          :style="{color:'#2E2E2E',fontSize:'25px',display:'inline-block',paddingRight:'15px'}"
          @click.stop="handlePreviewSingle"
        />
        <i
          class="el-icon-upload"
          :style="{color:'#2E2E2E',fontSize:'25px',display:'inline-block'}"
        />
      </div>
      <div
        ref="uploading"
        class="reupload"
        :style="{width:reuploadWidth+'px',height:reuploadWidth+'px','line-height':reuploadWidth+'px','font-size':reuploadWidth/5+'px'}"
      >
        上传中...
      </div>
      <div
        ref="failUpload"
        class="reupload"
        :style="{width:reuploadWidth+'px',height:reuploadWidth+'px','line-height':reuploadWidth+'px','font-size':reuploadWidth/5+'px'}"
      >
        上传失败
      </div>
    </el-upload>
    <!-- 多图片预览弹窗 -->
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl" alt="">
    </el-dialog>
    <!-- 剪裁组件弹窗 -->
    <el-dialog :visible.sync="cropperModel" width="1100px" :before-close="beforeClose">
      <Cropper
        ref="vueCropper"
        :img-file="file"
        :fixed-number="fixedNumber"
        :auto-crop-width="200"
        :auto-crop-height="200"
        @cropperImg="cropperImg"
      />
    </el-dialog>
  </div>
</template>
<script>
import Cropper from './cropper'
// import { fetchPolicy, getDateYmds, uploadImgData } from '@/api/upload'
import { fetchPolicy, uploadImgData } from '@/api/upload'
// import Axios from 'axios'
import Cookies from 'js-cookie'
import { Message } from 'element-ui'

export default {
  name: 'Uploader',
  components: {
    Cropper
  },
  props: {
    multiple: {
      // 多图开关
      type: Boolean,
      default: false
    },
    initUrl: {
      // 初始图片链接
      type: String,
      default: ''
    },
    fixedNumber: {
      // 剪裁框比例设置
      type: Array,
      default: function() {
        return [1, 1]
      }
    },
    width: {
      // 单图剪裁框宽度
      type: Number,
      default: 180
    },
    height: {
      // 单图剪裁框高度
      type: Number,
      default: 180
    }
  },
  data() {
    return {
      file: '', // 当前被选择的图片文件
      imageUrl: '', // 单图情况框内图片链接
      dialogImageUrl: '', // 多图情况弹窗内图片链接
      uploadList: [], // 上传图片列表
      reupload: true, // 控制"重新上传"开关
      dialogVisible: false, // 展示弹窗开关
      cropperModel: false, // 剪裁组件弹窗开关
      reuploadWidth: this.height * 0.8, // 动态改变”重新上传“大小
      fileId: 100,
      proUpload: {}
    }
  },
  watch: {
    initUrl: function(val) {
      // 监听传入初始化图片
      console.info('watch, initUrl === ', val)
      if (val) {
        if (typeof this.initUrl === 'string') {
          this.imageUrl = val
        } else {
          this.uploadList = this.formatImgArr(val)
          // this.$emit('imgupload', this.uploadList)
        }
      }
    }
  },
  updated() {
    if (this.$refs.vueCropper) {
      this.$refs.vueCropper.Update()
    }
  },
  mounted() {
    if (typeof this.initUrl === 'string') {
      this.imageUrl = this.initUrl
    } else {
      this.uploadList = this.formatImgArr(this.initUrl)
    }
  },
  methods: {
    /** ************** multiple多图情况 *********************/
    handlePreview(file) {
      // 点击进行图片展示
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
    handleRemove(file, fileList) {
      // 删除图片后更新图片文件列表并通知父级变化
      this.uploadList = fileList
      this.$emit('imgupload', this.uploadList)
      // this.$emit('imgupload', this.formatImgArr(this.uploadList))
    },
    /** *****************************************************/

    /** ***************** single单图情况 *********************/
    handlePreviewSingle(file) { // 点击进行图片展示
      this.dialogImageUrl = this.imageUrl
      this.dialogVisible = true
    },
    mouseEnter() { // 鼠标划入显示“重新上传”
      this.$refs.reupload.style.display = 'block'
      if (this.$refs.failUpload.style.display === 'block') {
        this.$refs.failUpload.style.display = 'none'
      }
      this.$refs.singleImg.style.opacity = '0.6'
    },
    mouseLeave() {
      // 鼠标划出隐藏“重新上传”
      this.$refs.reupload.style.display = 'none'
      this.$refs.singleImg.style.opacity = '1'
    },
    handleCrop(file, fileList) {
      // 点击弹出剪裁框
      this.cropperModel = true
      this.openCopper = !this.openCopper
      this.file = file
      // this.imageUrl = file.url
    },
    handleSuccess(response, file, fileList) {
      console.log(response, file)
    },
    handleError(err, file, fileList) {
      console.log(err, file, fileList)
    },
    /** ******************************************************/

    async cropperImg(data, type) {
      // 上传成功将照片传回父组件
      this.openCopper = false
      let currentPic
      if (type === 'blob') {
        currentPic = URL.createObjectURL(data)
      } else {
        currentPic = data
      }
      // data
      if (this.multiple) {
        this.uploadList.push({
          url: currentPic,
          uid: this.fileId++
        })
        this.$emit('imgupload', this.uploadList)// 根据自己实际项目需要将照片返回给父组件
        // this.uploadList.pop()
        // this.$emit('imgupload', this.formatImgArr(this.uploadList))
      } else {
        // this.$emit('imgupload', currentPic)
        // console.log('old-image-info', this.imageUrl)
        this.imageUrl = currentPic
      }
      this.$refs.vueCropper.isDisabled = false
      this.cropperModel = false
      this.uploadImage(this.imageUrl)
      this.$refs.uploading.style.display = 'none'
    },
    async beforeUpload() {
      console.log('---beforeUpload---')
      // 采取后端签名方式，获取的签名保存到cookies中，可以保证阿里云的安全性，账号不可见
      const sign = 'sign-upload'
      const signData = Cookies.get(sign)
      this.proUpload = new Promise((resolve, reject) => {
        // 从cookies中取签名，判断签名有没有过期
        if (signData === undefined) {
          fetchPolicy('article').then(response => {
            // console.log(response.data)
            Cookies.set(sign, JSON.stringify(response.data))
            resolve(response.data)
          }).catch(err => {
            console.log(err)
            reject(false)
          })
        } else {
          var response = JSON.parse(signData)
          var timestamp = Date.parse(new Date())
          if (response.expire - 3000 > timestamp) {
            // console.log('签名没过期')
            resolve(response)
          } else {
            // 签名过期的话重新请求签名
            fetchPolicy('article').then(response => {
              // console.log(response.data)
              Cookies.set(sign, JSON.stringify(response.data))
              resolve(response.data)
            }).catch(err => {
              console.log(err)
              reject(false)
            })
          }
        }
      })
    },
    async uploadImage(data) {
      // 自定义upload事件
      if (!this.multiple) {
        // 如果单图，则显示正在上传
        this.$refs.uploading.style.display = 'block'
      }
      const blobImg = this.dataURItoBlob(this.imageUrl)
      uploadImgData(blobImg).then(response => {
        if (response.status === 201) {
          const xmlObj = new DOMParser()
          const xmlDoc = xmlObj.parseFromString(response.data, 'text/xml')
          const imgUrl = xmlDoc.getElementsByTagName('Key')[0].childNodes[0].nodeValue

          this.$emit('getImgUrl', imgUrl)
        } else {
          Message({
            message: '图片上传失败！',
            type: 'error',
            duration: 5 * 1000
          })
        }
      })

      if (!this.multiple) {
        // 上传完成后隐藏正在上传
        this.$refs.uploading.style.display = 'none'
      }
    },
    async imgUpload(formData) {
      this.cropperModel = false
      this.$refs.uploading.style.display = 'none'
    },
    formatImgArr(arr) {
      const result = arr.map((item, index) => {
        if (typeof item === 'string') {
          return {
            url: item,
            uid: `index${index}`
          }
        } else {
          return item.url
        }
      })
      return result
    },
    beforeClose() {
      // this.uploadList.pop()
      // console.log(this.uploadList)
      this.openCopper = false
      this.cropperModel = false
    },
    // 压缩图片
    compress(img) {
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      // let initSize = img.src.length
      const width = img.width
      const height = img.height
      canvas.width = width
      canvas.height = height
      // 铺底色
      ctx.fillStyle = '#fff'
      ctx.fillRect(0, 0, canvas.width, canvas.height)
      ctx.drawImage(img, 0, 0, width, height)
      // 进行压缩
      const ndata = canvas.toDataURL('image/jpeg', 0.8)
      return ndata
    },
    // base64转成bolb对象
    dataURItoBlob(base64Data) {
      let byteString
      // console.log('base64Data ==393== : ', base64Data)
      if (base64Data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(base64Data.split(',')[1])
      } else {
        byteString = unescape(base64Data.split(',')[1])
      }
      const mimeString = base64Data.split(',')[0].split(':')[1].split('')[0]
      const ia = new Uint8Array(byteString.length)
      for (let i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i)
      }
      return new Blob([ia], { type: mimeString })
    }
  }
}
</script>
<style>
  .image-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    width: 180px;
    height: 180px;
  }
  .image-uploader .el-upload:hover {
    border-color: #409eff;
  }
  .image-uploader-icon {
    color: #8c939d;
    text-align: center;
  }
  .avatar {
    display: block;
  }
  .reupload {
    border-radius: 50%;
    position: absolute;
    color: #fff;
    background-color: #000000;
    opacity: 0.6;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: none;
  }
  #uploadIcon{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: none;
  }
</style>
